#pragma once
#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include <mysql/mysql.h>
#include <jsoncpp/json/json.h>
#include <sstream>
#include <istream>
#include <fstream>
#include <assert.h>
#include <memory>

#include "log.hpp"

using namespace std;

// 制作一个实用工具类，第一个编写的是Mysql语句的封装

class Mysql_util
{
public:
	static MYSQL *mysql_create(
		const string &hostname,
		const string &username,
		const string &password,
		const string &dbname,
		uint16_t port = 3306)
	{
		// 1.创建Mysql句柄
		MYSQL *Mysql = mysql_init(NULL);
		if (Mysql == NULL)
		{
			ELOG("Mysql Init failed!");
			return nullptr;
		}
		// 2.链接服务器

		if (mysql_real_connect(Mysql, hostname.c_str(), username.c_str(), password.c_str(), dbname.c_str(), port, NULL, 0) == NULL)
		{
			ELOG("Mysql Connect failed! %s ", mysql_error(Mysql));
			return nullptr;
		}

		// 3.链接成功，设置客户端字符集
		if (mysql_set_character_set(Mysql, "utf8") != 0)
		{
			ELOG("Set character failed! %s ", mysql_error(Mysql));
			mysql_close(Mysql);
			return nullptr;
		}

		return Mysql;
	}

	// 执⾏sql语句
	static bool Mysql_exec(MYSQL *mysql, const string &sql)
	{
		int ret = mysql_query(mysql, sql.c_str());
		if (ret != 0)
		{
			ELOG("mysql query failed! %s ", mysql_error(mysql));
			return false;
		}

		return true;
	}

	static bool Mysql_destroy(MYSQL *mysql)
	{
		if (mysql != nullptr)
		{
			mysql_close(mysql);
			return true;
		}

		ELOG("This sql hander is null!");
		return false;
	}

	~Mysql_util()
	{
	}

private:
};

class Json_util
{
public:
	// 1.将Json格式的数据序列化成整个字符串
	static bool serialize(const Json::Value &root, string &str)
	{
		// 1.1先将对应需要被序列化的数据以Json的格式填充好
		// 1.2 进行序列化，调用接口,Json使用的是工厂模式，我们需要一个工厂对象来生产出我们需要的功能对象
		Json::StreamWriterBuilder swb;
		unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
		stringstream ss;
		int ret = sw->write(root, &ss);
		if (ret != 0)
		{
			ELOG("Json write failed!");
			return false;
		}
		str = ss.str();
		return true;
	}

	// 2.将一整个字符串反序列化成为Json格式的数据
	static bool 	unserialize(string str, Json::Value &root)
	{
		Json::CharReaderBuilder crb;
		unique_ptr<Json::CharReader> cr(crb.newCharReader());
		// 2.4将传入的数据反序列化
		bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), &root, nullptr);
		if (ret == false)
		{
			ELOG("Json DeSerialize Failed!");
			return false;
		}

		return true;
	}
};

class Str_util
{
public:
	static int sepstring(const string &src, const string &sep, vector<string> &res)
	{
		// 123,56565,7,,,845
		// 查找分隔符的下标，然后放入对应的容器内。
		int pos = 0, mark = 0;

		while (mark < src.size())
		{
			pos = src.find(sep, mark);
			if (pos == src.npos)
			{
				// 没找到，说明是最后一个字串
				res.push_back(src.substr(mark));
				break;
			}
			if (pos == mark)
			{
				mark += sep.size();
				continue;
			}

			res.push_back(src.substr(mark, pos - mark));
			mark = pos + sep.size();
		}

		return res.size();
	}

private:
};

class File_util
{
public:
	static bool read( string& filename, string &getback)
	{
		// 先创建一个ifstream对象
		ifstream ifs(filename, ios::binary);
		// 打开文件以二进制打开，因为我们可能打开别的格式的文件，如果以默认字符为打开方式会出错

		if (!ifs.is_open())
		{
			ELOG("File %s [Open] Failed! ",filename.c_str());
			return false;
		}

		// 得到文件大小，以先跳转到文件末尾然后减去文件起始位置的偏移量来求得
		size_t fsize = 0;
		// 调整文件偏移量到文件末尾
		ifs.seekg(0, ios::end);
		fsize = ifs.tellg();
		// 再调整到开头
		ifs.seekg(0, ios::beg);

		getback.resize(fsize);


		// 读取数据
		ifs.read(&getback[0], fsize);
		if (!ifs.good())
		{
			ELOG("File [READ] Failed! ");
			ifs.close();
			return false;
		}
		ifs.close();

		return true;
	}
};

